﻿using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Xml;
using System.Windows.Input;
using System;
using SHomeWorkshop.LunarConcept.Controls;
using SHomeWorkshop.LunarConcept.Adorners;
using SHomeWorkshop.LunarConcept.Tools;
using SHomeWorkshop.LunarConcept.Enums;
using SHomeWorkshop.LunarConcept.Widgets.Interfaces;
using System.Collections.Generic;
using SHomeWorkshop.LunarMind;

namespace SHomeWorkshop.LunarConcept.Widgets
{
    /// <summary>
    /// 创建时间：2012年1月18日
    /// 创建者：  杨震宇
    /// 
    /// 主要用途：折线部件。
    /// </summary>
    public class PolyLineWidget : ArrowLineWidget, Interfaces.ICanSameSize, Interfaces.ILinkableLine
    {
        #region 构造方法=====================================================================================================

        /// <summary>
        /// [静态构造方法]
        /// </summary>
        static PolyLineWidget()
        {
            dashArray = new DoubleCollection() { 2, 2 };
        }

        /// <summary>
        /// [构造方法]
        /// </summary>
        public PolyLineWidget(PageEditorReader masterEditor)
            : base(masterEditor)
        {
            widgetType = Enums.WidgetTypes.PolyLine;
            widgetClassLocalName = Widget.GetWidgetClassLocalName(this.GetType().Name);

            mainPath.Data = new PathGeometry();
            mainPathFigure = new PathFigure() { IsClosed = false };
            (mainPath.Data as PathGeometry).Figures.Add(mainPathFigure);
            mainPathFigure.Segments.Add(mainPolySegment);

            mainPath.Fill = null;
            mainPath.Stroke = WidgetForeColor;
            
            this.mainCanvas.Children.Add(mainPath);

            Canvas.SetZIndex(mainPath, 0);

            #region 两个箭头。
            //startArrowPath.Cursor = Cursors.Arrow;
            startArrowPath.Fill = startArrowPath.Stroke = WidgetForeColor;
            startArrowPath.StrokeThickness = widgetLineWidth;
            PathGeometry startArrowPg = new PathGeometry();
            startArrowPath.Data = startArrowPg;

            startArrowPathFigure.IsClosed = true;
            startArrowPathFigure.IsFilled = true;
            startArrowPathFigure.Segments.Add(startArrowPolyLineSegment);

            startArrowPg.Figures.Add(startArrowPathFigure);

            //endArrowPath.Cursor = Cursors.Arrow;
            endArrowPath.Fill = endArrowPath.Stroke = WidgetForeColor;
            endArrowPath.StrokeThickness = widgetLineWidth;
            PathGeometry endArrowPg = new PathGeometry();
            endArrowPath.Data = endArrowPg;

            endArrowPathFigure.IsClosed = true;
            endArrowPathFigure.IsFilled = true;
            endArrowPathFigure.Segments.Add(endArrowPolyLineSegment);

            endArrowPg.Figures.Add(endArrowPathFigure);

            mainCanvas.Children.Add(startArrowPath);
            mainCanvas.Children.Add(endArrowPath);

            Canvas.SetZIndex(startArrowPath, 1);
            Canvas.SetZIndex(endArrowPath, 1);
            #endregion
            
            this.commentAdorner = new CommentAdorner(this.mainPath, this) { Visibility = System.Windows.Visibility.Collapsed };//默认不显示。

            this.hyperLinkAdorner = new HyperLinkAdorner(this.mainPath, this) { Visibility = Visibility.Collapsed };
            this.hyperLinkAdorner.MouseLeftButtonUp += new MouseButtonEventHandler(hyperLinkAdorner_MouseLeftButtonUp);

            AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this.mainCanvas);
            if (adornerLayer == null)
            {
                MessageBox.Show("　　未找到Widget的装饰层！", Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
            }
            else
            {
                adornerLayer.Add(this.commentAdorner);//这个要在各具体部件类中添加。
                adornerLayer.Add(this.hyperLinkAdorner);//这个要在各具体部件类中添加。
            }
        }

        #endregion


        #region 字段与属性===================================================================================================

        public override Point BottomRight
        {
            get
            {
                double minLeft, minTop, maxRight, maxBottom;

                minLeft = Math.Min(Math.Min(startPoint.X, endPoint.X), centerCPPoint.X);
                maxRight = Math.Max(Math.Max(startPoint.X, endPoint.X), centerCPPoint.X);

                minTop = Math.Min(Math.Min(startPoint.Y, endPoint.Y), centerCPPoint.Y);
                maxBottom = Math.Max(Math.Max(startPoint.Y, endPoint.Y), centerCPPoint.Y);

                return new Point(maxRight, maxBottom);
            }
        }

        private Point centerBasePoint;
        
        private Point centerCPPoint = new Point();
        [Tools.LunarProperty("CenterCPPoint", PropertyDateType.Point)]
        public Point CenterCPPoint
        {
            get { return centerCPPoint; }
            set
            {
                centerCPPoint = FormatPoint(value);

                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.CenterCPPointTag, centerCPPoint.ToString());
                }

                RefreshLocation();
            }
        }
        
        private Orientation direction = Orientation.Vertical;
        /// <summary>
        /// 指出三折线中间一段是水平方向还是垂直向。
        /// </summary>
        [Tools.LunarProperty("Direction", PropertyDateType.Orientation)]
        public Orientation Direction
        {
            get { return direction; }
            set
            {
                direction = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.DirectionTag, value.ToString());
                }
                RefreshLocation();
            }
        }

        private ControlDraggingType draggingType = ControlDraggingType.None;
        /// <summary>
        /// [只读]正在拖动哪个控制点。
        /// </summary>
        public ControlDraggingType DraggingType
        {
            get { return draggingType; }
        }

        private Point endBasePoint;
        
        private Point endPoint = new Point();
        /// <summary>
        /// [读写]线的终点坐标。
        /// </summary>
        [Tools.LunarProperty("EndPoint", PropertyDateType.Point)]
        public Point EndPoint
        {
            get { return endPoint; }
            set
            {
                endPoint = FormatPoint(value);

                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.EndPointTag, endPoint.ToString());
                }

                RefreshLocation();
            }
        }

        private PolyLineForms lineForm = PolyLineForms.PolyLine;
        /// <summary>
        /// [读写]画成思维导图线。此属性总是可以设置的，
        /// 但必须在作为连接线时才起作用（以IsLinked为前提）。
        /// </summary>
        [Tools.LunarProperty("LineForm", PropertyDateType.PolyLineForm)]
        public PolyLineForms LineForm
        {
            get { return lineForm; }
            set
            {
                lineForm = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.LineFormTag, value.ToString());
                }

                this.RefreshLineForm();
            }
        }

        /// <summary>
        /// [只读]是否被挂接到两个ContentWidget。
        /// </summary>
        public bool IsLinked
        {
            get
            {
                if (startMasterId == string.Empty && endMasterId == string.Empty)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
        }

        /// <summary>
        /// 连接线永不被设置为锁定。
        /// </summary>
        [Tools.LunarProperty("IsLocked", PropertyDateType.Bool)]
        public override bool IsLocked
        {
            get
            {
                if (IsLinked) return false;

                return base.IsLocked;
            }
            set
            {
                if (IsLinked) return;//连接线不被设置为锁定。

                base.IsLocked = value;
            }
        }
        
        private bool isTextAtLeftOrTop = true;
        /// <summary>
        /// [读写]文本区是否位于左侧或顶侧。若为false则位于右侧或底侧。默认为true。
        /// </summary>
        [LunarProperty("IsTextAtLeftOrTop", PropertyDateType.Bool)]
        public bool IsTextAtLeftOrTop
        {
            get { return isTextAtLeftOrTop; }
            set
            {
                isTextAtLeftOrTop = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.IsTextAtLeftOrTopTag, value.ToString());
                }
                this.RefreshTextPanelLocatin();
            }
        }

        private Path mainPath = new Path() { Cursor = Cursors.Hand };

        public Path MainPath
        {
            get { return mainPath; }
        }

        private PathFigure mainPathFigure;

        public PathFigure MainPathFigure
        {
            get { return mainPathFigure; }
        }

        private PolyLineSegment mainPolySegment = new PolyLineSegment();
        
        private Point startBasePoint;

        private Point startPoint = new Point(0, 0);
        /// <summary>
        /// [读写]线的起点坐标。
        /// </summary>
        [Tools.LunarProperty("StartPoint", PropertyDateType.Point)]
        public Point StartPoint
        {
            get { return startPoint; }
            set
            {
                startPoint = FormatPoint(value);

                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.StartPointTag, startPoint.ToString());
                }

                RefreshLocation();
            }
        }


        private string startMasterId = string.Empty;
        /// <summary>
        /// [读写]首端点挂接的部件的Id。
        /// </summary>
        [Tools.LunarProperty("StartMasterId", PropertyDateType.String)]
        public string StartMasterId
        {
            get { return startMasterId; }
            set
            {
                startMasterId = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.StartMasterIdTag, value);
                }
            }
        }

        private string endMasterId = string.Empty;
        /// <summary>
        /// [读写]尾端点挂接到的部件的Id。
        /// </summary>
        [Tools.LunarProperty("EndMasterId", PropertyDateType.String)]
        public string EndMasterId
        {
            get { return endMasterId; }
            set
            {
                endMasterId = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.EndMasterIdTag, value);
                }
            }
        }

        public override Point TopLeft
        {
            get
            {
                double minLeft, minTop, maxRight, maxBottom;

                minLeft = Math.Min(Math.Min(startPoint.X, endPoint.X), centerCPPoint.X);
                maxRight = Math.Max(Math.Max(startPoint.X, endPoint.X), centerCPPoint.X);

                minTop = Math.Min(Math.Min(startPoint.Y, endPoint.Y), centerCPPoint.Y);
                maxBottom = Math.Max(Math.Max(startPoint.Y, endPoint.Y), centerCPPoint.Y);

                return new Point(minLeft, minTop);
            }
        }

        #endregion


        #region 方法=========================================================================================================

        public override void Build()
        {
            base.Build();

            if (this.xmlData == null) return;

            XmlAttribute attrStartMasterId = this.xmlData.GetAttribute(XmlTags.StartMasterIdTag);
            if (attrStartMasterId != null)
            {
                this.startMasterId = attrStartMasterId.Value;
            }

            XmlAttribute attrEndMasterId = this.xmlData.GetAttribute(XmlTags.EndMasterIdTag);
            if (attrEndMasterId != null)
            {
                this.endMasterId = attrEndMasterId.Value;
            }

            XmlAttribute attrStartPoint = this.xmlData.GetAttribute(XmlTags.StartPointTag);
            if (attrStartPoint != null)
            {
                this.startPoint = FormatPoint(Point.Parse(attrStartPoint.Value));
            }

            XmlAttribute attrCenterCPPoint = this.xmlData.GetAttribute(XmlTags.CenterCPPointTag);
            if (attrCenterCPPoint != null)
            {
                this.centerBasePoint = this.centerCPPoint = FormatPoint(Point.Parse(attrCenterCPPoint.Value));
            }

            XmlAttribute attrEndPoint = this.xmlData.GetAttribute(XmlTags.EndPointTag);
            if (attrEndPoint != null)
            {
                this.endPoint = FormatPoint(Point.Parse(attrEndPoint.Value));
            }

            XmlAttribute attrDirection = this.xmlData.GetAttribute(XmlTags.DirectionTag);
            if (attrDirection != null)
            {
                this.direction = (Orientation)Enum.Parse(typeof(Orientation), attrDirection.Value);
            }

            XmlAttribute attrIsTextAtLeftOrTop = this.xmlData.GetAttribute(XmlTags.IsTextAtLeftOrTopTag);
            if (attrIsTextAtLeftOrTop != null)
            {
                this.isTextAtLeftOrTop = bool.Parse(attrIsTextAtLeftOrTop.Value);
            }

            XmlAttribute attrLineForm = this.xmlData.GetAttribute(XmlTags.LineFormTag);
            if (attrLineForm != null)
            {
                this.lineForm = (Enums.PolyLineForms)Enum.Parse(typeof(Enums.PolyLineForms), attrLineForm.Value);
            }

            //包含RefreshArrows()调用。
            this.RefreshLocation();

            //此类是下面这几个属性的“最终实现类”。这些属性的值都已在基类确定。因此调用,
            this.RefreshWidgetLineColor();
            this.RefreshWidgetLineWidth();
            this.RefreshLineDash();

        }
                
        /// <summary>
        /// 根据“IsLinked”的结果分别重绘线条。
        /// </summary>
        public void DrawLine()
        {
            if (masterEditor == null) return;
            if (IsLinked)
            {
                Widget startWidget = masterEditor.GetWidget(this.StartMasterId);
                Widget endWidget = masterEditor.GetWidget(this.EndMasterId);
                if (startWidget == null || endWidget == null)
                {
                    DrawLine(this.startPoint, this.centerCPPoint, this.endPoint);
                    return;
                }

                Rect startRect = startWidget.OuterRect;
                Rect endRect = endWidget.OuterRect;
                DrawLine(startRect, endRect);//只有被链接的才会调用。链接时centerCPPoint无意义。
            }
            else
            {
                DrawLine(this.startPoint, this.centerCPPoint, this.endPoint);
            }
        }

        /// <summary>
        /// “IsLinked”为false时，表示此线未连接到ICanLinkedWidget部件。
        /// </summary>
        /// <param name="startPoint">首端点。</param>
        /// <param name="startCPPoint">中段线控制点。</param>
        /// <param name="endPoint">尾端点。</param>
        private void DrawLine(Point startPoint, Point centerCPPoint, Point endPoint)
        {
            switch (direction)
            {
                case Orientation.Vertical:
                    {
                        startBasePoint = new Point(centerCPPoint.X, startPoint.Y);
                        endBasePoint = new Point(centerCPPoint.X, endPoint.Y);
                        centerBasePoint = new Point(centerCPPoint.X,
                            startBasePoint.Y + (endBasePoint.Y - startBasePoint.Y) / 2);
                        break;
                    }
                default://水平
                    {
                        startBasePoint = new Point(startPoint.X, centerCPPoint.Y);
                        endBasePoint = new Point(endPoint.X, centerCPPoint.Y);
                        centerBasePoint = new Point(startBasePoint.X + (endBasePoint.X - startBasePoint.X) / 2,
                            centerCPPoint.Y);
                        break;
                    }
            }

            if (arrows == ArrowType.None)
            {
                mainPathFigure.StartPoint = startPoint;
                mainPolySegment.Points = new PointCollection()
                {
                    startBasePoint,endBasePoint,endPoint,
                };
            }
            else
            {
                if (arrows == ArrowType.All || arrows == ArrowType.Start)
                {
                    startArrowPathFigure.StartPoint = startPoint;
                    Tools.ArrowPoints apStart = new Tools.ArrowPoints(
                        startArrowPathFigure.StartPoint, startBasePoint, widgetLineWidth * 2);

                    startArrowPolyLineSegment.Points = new PointCollection(){
                        apStart.ArrowLeftPoint,apStart.ArrowRightPoint,
                    };
                    mainPathFigure.StartPoint = apStart.ArrowRealTopPoint;
                }
                else
                {
                    mainPathFigure.StartPoint = startPoint;
                }

                if (arrows == ArrowType.All || arrows == ArrowType.End)
                {
                    endArrowPathFigure.StartPoint = endPoint;
                    Tools.ArrowPoints apEnd = new Tools.ArrowPoints(
                        endArrowPathFigure.StartPoint, endBasePoint, widgetLineWidth * 2);

                    endArrowPolyLineSegment.Points = new PointCollection(){
                        apEnd.ArrowLeftPoint,apEnd.ArrowRightPoint,
                    };
                    endPoint = apEnd.ArrowRealTopPoint;
                }
                //else
                //{
                //    endPoint = endPoint;//不变
                //}

                mainPolySegment.Points = new PointCollection()
                {
                    startBasePoint,endBasePoint,endPoint,
                };
            }

            //刷新文本块位置
            LocateTextPanel(startBasePoint, endBasePoint, this.direction);
        }

        /// <summary>
        /// ★此方法不会调用DrawLine(Point,Point,Point,Point)方法来进行绘制（会重复计算坐标点，效率较低）。
        /// ★应保持此方法与重载版本行为一致！！！
        /// 
        /// “IsLinked”属性为true时，曲线被连接到两个ICanLinkedWidget部件。
        /// 此时，曲线的位置和形状由这两个部件的外框和曲线的两个控制点决定。
        /// 曲线的首端点、尾端点将自动计算，计算的规则是：“首控制点到首矩形的中心点与矩形的交战为首端点”。
        /// </summary>
        /// <param name="startRect">首连接部件外框。</param>
        /// <param name="endRect">尾连接部件外框。</param>
        private void DrawLine(Rect startRect, Rect endRect)
        {
            startRect.X -= 4; startRect.Y -= 4; startRect.Width += 8; startRect.Height += 8;
            endRect.X -= 4; endRect.Y -= 4; endRect.Width += 8; endRect.Height += 8;

            if (startRect.IntersectsWith(endRect))
            {
                startArrowPath.Visibility = endArrowPath.Visibility =
                mainPath.Visibility = Visibility.Hidden;
            }
            else
            {
                mainPath.Visibility = Visibility.Visible;

                //看看能否按FishBone方式或C形线（匚形线）方式来绘制
                //如果可以，就按FishBone来绘制，否则继续
                switch (lineForm)
                {
                    case PolyLineForms.BigFishBone:
                        {
                            //如果空间不够绘制鱼骨图中骨，则按普通折线绘制
                            if (DrawBigFishBone(startRect, endRect)) return;
                            else break;
                        }
                    case PolyLineForms.MediumFishBone:
                        {
                            //如果空间不够绘制鱼骨图中骨，则按普通折线绘制
                            if (DrawMediumFishBone(startRect, endRect)) return;
                            else break;
                        }
                    case PolyLineForms.CLine:
                        {
                            if (DrawCLine(startRect, endRect)) return;
                            else break;
                        }
                    case PolyLineForms.LLine:
                        {
                            if (DrawLLine(startRect, endRect)) return;
                            else break;
                        }
                    //case PolyLineForms.PolyLine: break;//直接继续绘制
                    default: break;
                }

                switch (arrows)
                {
                    case ArrowType.All:
                        {
                            startArrowPath.Visibility = endArrowPath.Visibility = Visibility.Visible; break;
                        }
                    case ArrowType.End:
                        {
                            startArrowPath.Visibility = Visibility.Hidden;
                            endArrowPath.Visibility = Visibility.Visible;
                            break;
                        }
                    case ArrowType.Start:
                        {
                            startArrowPath.Visibility = Visibility.Visible;
                            endArrowPath.Visibility = Visibility.Hidden;
                            break;
                        }
                    case ArrowType.None:
                        {
                            startArrowPath.Visibility = endArrowPath.Visibility = Visibility.Hidden; break;
                        }
                }

                mainPath.Visibility = Visibility.Visible;
            }

            Point startCenter = new Point(startRect.Left + startRect.Width / 2,
                startRect.Top + startRect.Height / 2);
            Point endCenter = new Point(endRect.Left + endRect.Width / 2,
                endRect.Top + endRect.Height / 2);

            Tools.PointToRect.ArrowPoints aptStart = Tools.PointToRect.GetCrossPointToRect(startRect, endCenter);
            Tools.PointToRect.ArrowPoints aptEnd = Tools.PointToRect.GetCrossPointToRect(endRect, startCenter);

            Point tmpStartPt;
            Point tmpEndPt;

            //两个矩形不相交，又分这样几种情况：
            //１.如果两个矩形之间水平方向上有部分重叠；——此时折线中段只能纵向。取左、右边中点。
            //２.如果两个矩形之间垂直方向上有部分重叠；——此时折线中段只能横向。取顶、底边中点。
            //３.如果两个矩形之间没有任何重叠；此时由折线自身决定中段线的方向。据此决定取哪两个边的中点。

            if ((startRect.Bottom >= endRect.Top && startRect.Bottom <= endRect.Bottom) ||
                (startRect.Top >= endRect.Top && startRect.Top <= endRect.Bottom) ||
                (endRect.Bottom >= startRect.Top && endRect.Bottom <= startRect.Bottom) ||
                (endRect.Top >= startRect.Top && endRect.Top <= startRect.Bottom))
            {
                //水平方向上至少有部分重叠：
                if (aptStart.Top.X < startCenter.X)
                {
                    tmpStartPt = new Point(startRect.Left - 2, startCenter.Y);
                }
                else
                {
                    tmpStartPt = new Point(startRect.Right + 2, startCenter.Y);
                }

                if (aptEnd.Top.X < endCenter.X)
                {
                    tmpEndPt = new Point(endRect.Left - 2, endCenter.Y);
                }
                else
                {
                    tmpEndPt = new Point(endRect.Right + 2, endCenter.Y);
                }

                this.startPoint =
                mainPathFigure.StartPoint = FormatPoint(tmpStartPt);
                startBasePoint = FormatPoint(new Point(tmpStartPt.X + (tmpEndPt.X - tmpStartPt.X) / 2, tmpStartPt.Y));
                endBasePoint = FormatPoint(new Point(startBasePoint.X, tmpEndPt.Y));

                tmpEndPt = FormatPoint(tmpEndPt);

                mainPolySegment.Points = new PointCollection()
                {
                    startBasePoint,endBasePoint,tmpEndPt,
                };

                this.centerBasePoint = new Point(startBasePoint.X + (endBasePoint.X - startBasePoint.X) / 2,
                    startBasePoint.Y + (endBasePoint.Y - startBasePoint.Y) / 2);

                this.centerCPPoint = centerBasePoint;
                this.endPoint = tmpEndPt;

                LocateTextPanel(startBasePoint, endBasePoint, Orientation.Vertical);
            }
            else
            {
                if ((startRect.Left >= endRect.Left && startRect.Left <= endRect.Right) ||
                    (startRect.Right >= endRect.Left && startRect.Right <= endRect.Right) ||
                    (endRect.Left >= startRect.Left && endRect.Left <= startRect.Right) ||
                    (endRect.Right >= startRect.Left && endRect.Right <= startRect.Right))
                {
                    //垂直方向至少有部分重叠，中段线只能横向：
                    if (aptStart.Top.Y < startCenter.Y)
                    {
                        tmpStartPt = new Point(startCenter.X, startRect.Top - 2);
                    }
                    else
                    {
                        tmpStartPt = new Point(startCenter.X, startRect.Bottom + 2);
                    }

                    if (aptEnd.Top.Y < endCenter.Y)
                    {
                        tmpEndPt = new Point(endCenter.X, endRect.Top - 2);
                    }
                    else
                    {
                        tmpEndPt = new Point(endCenter.X, endRect.Bottom + 2);
                    }

                    this.startPoint =
                    mainPathFigure.StartPoint = FormatPoint(tmpStartPt);
                    startBasePoint = FormatPoint(new Point(tmpStartPt.X, tmpStartPt.Y + (tmpEndPt.Y - tmpStartPt.Y) / 2));
                    endBasePoint = FormatPoint(new Point(tmpEndPt.X, startBasePoint.Y));

                    tmpEndPt = FormatPoint(tmpEndPt);

                    mainPolySegment.Points = new PointCollection()
                    {
                        startBasePoint,endBasePoint, tmpEndPt,
                    };

                    this.centerBasePoint = new Point(startBasePoint.X + (endBasePoint.X - startBasePoint.X) / 2,
                        startBasePoint.Y + (endBasePoint.Y - startBasePoint.Y) / 2);

                    this.centerCPPoint = centerBasePoint;
                    this.endPoint = tmpEndPt;

                    LocateTextPanel(startBasePoint, endBasePoint, Orientation.Horizontal);
                }
                else
                {
                    //没有任何重叠：
                    if (direction == Orientation.Horizontal)
                    {
                        if (endCenter.Y > startCenter.Y)
                        {
                            tmpStartPt = new Point(startCenter.X, startRect.Bottom + 2);
                            tmpEndPt = new Point(endCenter.X, endRect.Top - 2);
                        }
                        else
                        {
                            tmpStartPt = new Point(startCenter.X, startRect.Top - 2);
                            tmpEndPt = new Point(endCenter.X, endRect.Bottom + 2);
                        }

                        this.startPoint =
                        mainPathFigure.StartPoint = FormatPoint(tmpStartPt);
                        startBasePoint = FormatPoint(new Point(tmpStartPt.X, tmpStartPt.Y + (tmpEndPt.Y - tmpStartPt.Y) / 2));
                        endBasePoint = FormatPoint(new Point(tmpEndPt.X, startBasePoint.Y));

                        tmpEndPt = FormatPoint(tmpEndPt);

                        mainPolySegment.Points = new PointCollection()
                        {
                            startBasePoint,endBasePoint, tmpEndPt,
                        };
                    }
                    else
                    {
                        if (endCenter.X > startCenter.X)
                        {
                            tmpStartPt = new Point(startRect.Right + 2, startCenter.Y);
                            tmpEndPt = new Point(endRect.Left - 2, endCenter.Y);
                        }
                        else
                        {
                            tmpStartPt = new Point(startRect.Left - 2, startCenter.Y);
                            tmpEndPt = new Point(endRect.Right + 2, endCenter.Y);
                        }

                        this.startPoint =
                        mainPathFigure.StartPoint = FormatPoint(tmpStartPt);
                        startBasePoint = FormatPoint(new Point(tmpStartPt.X + (tmpEndPt.X - tmpStartPt.X) / 2, tmpStartPt.Y));
                        endBasePoint = FormatPoint(new Point(startBasePoint.X, tmpEndPt.Y));

                        tmpEndPt = FormatPoint(tmpEndPt);

                        mainPolySegment.Points = new PointCollection()
                        {
                            startBasePoint,endBasePoint, tmpEndPt,
                        };
                    }

                    this.centerBasePoint = new Point(startBasePoint.X + (endBasePoint.X - startBasePoint.X) / 2,
                        startBasePoint.Y + (endBasePoint.Y - startBasePoint.Y) / 2);

                    this.centerCPPoint = centerBasePoint;
                    this.endPoint = tmpEndPt;

                    //只有这里，部件定义的中段线direction才是有效的。
                    LocateTextPanel(startBasePoint, endBasePoint, this.direction);
                }
            }

            //重新计算箭头位置。
            startArrowPathFigure.StartPoint = FormatPoint(tmpStartPt);
            Tools.ArrowPoints apStart = new Tools.ArrowPoints(
                    startArrowPathFigure.StartPoint, startBasePoint, widgetLineWidth * 2);

            startArrowPolyLineSegment.Points = new PointCollection()
            {
                apStart.ArrowLeftPoint,apStart.ArrowRightPoint,
            };
            mainPathFigure.StartPoint = apStart.ArrowRealTopPoint;

            endArrowPathFigure.StartPoint = FormatPoint(tmpEndPt);
            Tools.ArrowPoints apEnd = new Tools.ArrowPoints(
                endArrowPathFigure.StartPoint, endBasePoint, widgetLineWidth * 2);
            this.endArrowPolyLineSegment.Points = new PointCollection()
            {
                apEnd.ArrowLeftPoint,apEnd.ArrowRightPoint,
            };
            
            //刷新文本块位置不能放在此处，而需要根据中段线的自动定位状态来决定文本放置位置。
        }

        /// <summary>
        /// 绘制C形线（匚形线）。只在作连接线时有效。
        /// </summary>
        /// <param name="startRect">首挂接节点区域。</param>
        /// <param name="endRect">尾挂接节点区域。</param>
        private bool DrawCLine(Rect startRect, Rect endRect)
        {
            double padding = this.widgetLineWidth;
            endRect = new Rect(endRect.X - padding, endRect.Y - padding, endRect.Width + 2 * padding, endRect.Height + 2 * padding);

            Point startCenter = new Point(startRect.X + startRect.Width / 2, startRect.Y + startRect.Height / 2);
            Point endCenter = new Point(endRect.X + endRect.Width / 2, endRect.Y + endRect.Height / 2);

            Point startPoint;
            Point endPoint;

            switch (this.Direction)
            {
                case Orientation.Horizontal:
                    {
                        if (startCenter.Y <= endCenter.Y)//中段线在顶部
                        {
                            double top = Math.Min(startRect.Top - 20, endRect.Top - 20);
                            startPoint = FormatPoint(new Point(startCenter.X, startRect.Top));
                            endPoint = FormatPoint(new Point(endCenter.X, endRect.Top));
                            this.startBasePoint = FormatPoint(new Point(startCenter.X, top));
                            this.endBasePoint = FormatPoint(new Point(endCenter.X, top));
                            centerBasePoint = FormatPoint(new Point(startBasePoint.X + (endBasePoint.X - startBasePoint.X) / 2, startBasePoint.Y));
                        }
                        else//中段线在底部
                        {
                            double bottom = Math.Max(startRect.Bottom + 20, endRect.Bottom + 20);
                            startPoint = FormatPoint(new Point(startCenter.X, startRect.Bottom));
                            endPoint = FormatPoint(new Point(endCenter.X, endRect.Bottom));
                            this.startBasePoint = FormatPoint(new Point(startCenter.X, bottom));
                            this.endBasePoint = FormatPoint(new Point(endCenter.X, bottom));
                            centerBasePoint = FormatPoint(new Point(startBasePoint.X + (endBasePoint.X - startBasePoint.X) / 2, startBasePoint.Y));
                        }
                        break;
                    }
                default:
                    {
                        if (startCenter.X <= endCenter.X)//中段线在左侧
                        {
                            double left = Math.Min(startRect.Left - 20, endRect.Left - 20);
                            startPoint = FormatPoint(new Point(startRect.Left, startCenter.Y));
                            endPoint = FormatPoint(new Point(endRect.Left, endCenter.Y));
                            this.startBasePoint = FormatPoint(new Point(left, startCenter.Y));
                            this.endBasePoint = FormatPoint(new Point(left, endCenter.Y));
                            centerBasePoint = FormatPoint(new Point(startBasePoint.X, startBasePoint.Y + (endBasePoint.Y - startBasePoint.Y) / 2));
                        }
                        else//中段线在右侧
                        {
                            double right = Math.Max(startRect.Right + 20, endRect.Right + 20);
                            startPoint = FormatPoint(new Point(startRect.Right, startCenter.Y));
                            endPoint = FormatPoint(new Point(endRect.Right, endCenter.Y));
                            this.startBasePoint = FormatPoint(new Point(right, startCenter.Y));
                            this.endBasePoint = FormatPoint(new Point(right, endCenter.Y));
                            centerBasePoint = FormatPoint(new Point(startBasePoint.X, startBasePoint.Y + (endBasePoint.Y - startBasePoint.Y) / 2));
                        }
                        break;
                    }
            }

            this.mainPathFigure.StartPoint = startPoint;
            this.mainPolySegment.Points = new PointCollection(){
                this.startBasePoint,this.endBasePoint,endPoint,
            };
            

            //只有这里，部件定义的中段线direction才是有效的。
            LocateTextPanel(this.startBasePoint, this.endBasePoint, this.direction);

            switch (arrows)
            {
                case ArrowType.All:
                    {
                        startArrowPath.Visibility = endArrowPath.Visibility = Visibility.Visible; break;
                    }
                case ArrowType.End:
                    {
                        startArrowPath.Visibility = Visibility.Hidden;
                        endArrowPath.Visibility = Visibility.Visible;
                        break;
                    }
                case ArrowType.Start:
                    {
                        startArrowPath.Visibility = Visibility.Visible;
                        endArrowPath.Visibility = Visibility.Hidden;
                        break;
                    }
                case ArrowType.None:
                    {
                        startArrowPath.Visibility = endArrowPath.Visibility = Visibility.Hidden; break;
                    }
            }

            //重新计算箭头位置。
            startArrowPathFigure.StartPoint = startPoint;
            Tools.ArrowPoints apStart = new Tools.ArrowPoints(
                    startArrowPathFigure.StartPoint, startBasePoint, widgetLineWidth * 2);

            startArrowPolyLineSegment.Points = new PointCollection()
            {
                apStart.ArrowLeftPoint,apStart.ArrowRightPoint,
            };
            mainPathFigure.StartPoint = apStart.ArrowRealTopPoint;

            endArrowPathFigure.StartPoint = endPoint;
            Tools.ArrowPoints apEnd = new Tools.ArrowPoints(
                endArrowPathFigure.StartPoint, endBasePoint, widgetLineWidth * 2);
            this.endArrowPolyLineSegment.Points = new PointCollection()
            {
                apEnd.ArrowLeftPoint,apEnd.ArrowRightPoint,
            };

            return true;
        }

        /// <summary>
        /// 绘制L形线（∟形线|拐形线）。只在作连接线时有效。
        /// </summary>
        /// <param name="startRect">首挂接节点区域。</param>
        /// <param name="endRect">尾挂接节点区域。</param>
        private bool DrawLLine(Rect startRect, Rect endRect)
        {
            double padding = this.widgetLineWidth;
            endRect = new Rect(endRect.X - padding, endRect.Y - padding, endRect.Width + 2 * padding, endRect.Height + 2 * padding);

            Point startCenter = new Point(startRect.X + startRect.Width / 2, startRect.Y + startRect.Height / 2);
            Point endCenter = new Point(endRect.X + endRect.Width / 2, endRect.Y + endRect.Height / 2);

            Point startPoint;
            Point endPoint;

            switch (this.Direction)
            {
                case Orientation.Horizontal:
                    {
                        if (startCenter.X <= endCenter.X)//EndRect在右侧
                        {
                            if (startCenter.Y <= endCenter.Y)//End在右下
                            {
                                startPoint = this.FormatPoint(new Point(startRect.Right, startCenter.Y));
                                endPoint = this.FormatPoint(new Point(endCenter.X, endRect.Top));
                            }
                            else//End在右上
                            {
                                startPoint = this.FormatPoint(new Point(startRect.Right, startCenter.Y));
                                endPoint = this.FormatPoint(new Point(endCenter.X, endRect.Bottom));
                            }
                        }
                        else//EndRect在左侧
                        {
                            if (startCenter.Y <= endCenter.Y)//End在左下
                            {
                                startPoint = this.FormatPoint(new Point(startRect.Left, startCenter.Y));
                                endPoint = this.FormatPoint(new Point(endCenter.X, endRect.Top));
                            }
                            else//End在左上
                            {
                                startPoint = this.FormatPoint(new Point(startRect.Left, startCenter.Y));
                                endPoint = this.FormatPoint(new Point(endCenter.X, endRect.Bottom));
                            }
                        }

                        this.startBasePoint =
                            this.endBasePoint = new Point(endPoint.X, startPoint.Y);

                        //注意：this.centerBasePoint的取值不是中段线而是末段线：
                        this.centerBasePoint = this.FormatPoint(new Point(
                            endPoint.X, endPoint.Y + (startPoint.Y - endPoint.Y) / 2));
                        break;
                    }
                default:
                    {
                        if (startCenter.X <= endCenter.X)//EndRect在右侧
                        {
                            if (startCenter.Y <= endCenter.Y)//End在右下
                            {
                                startPoint = this.FormatPoint(new Point(startCenter.X, startRect.Bottom));
                                endPoint = this.FormatPoint(new Point(endRect.Left, endCenter.Y));
                            }
                            else//End在右上
                            {
                                startPoint = this.FormatPoint(new Point(startCenter.X, startRect.Top));
                                endPoint = this.FormatPoint(new Point(endRect.Left, endCenter.Y));
                            }
                        }
                        else//EndRect在左侧
                        {
                            if (startCenter.Y <= endCenter.Y)//End在左下
                            {
                                startPoint = this.FormatPoint(new Point(startCenter.X, startRect.Bottom));
                                endPoint = this.FormatPoint(new Point(endRect.Right, endCenter.Y));
                            }
                            else//End在左上
                            {
                                startPoint = this.FormatPoint(new Point(startCenter.X, startRect.Top));
                                endPoint = this.FormatPoint(new Point(endRect.Right, endCenter.Y));
                            }
                        }

                        this.startBasePoint =
                            this.endBasePoint = new Point(startPoint.X, endPoint.Y);
                        this.centerBasePoint = this.FormatPoint(new Point(
                            endPoint.X + (startPoint.X - endPoint.X) / 2, endPoint.Y));
                        break;
                    }
            }

            this.mainPathFigure.StartPoint = startPoint;
            this.mainPolySegment.Points = new PointCollection(){
                this.startBasePoint,this.endBasePoint,endPoint,
            };
            
            //只有这里，部件定义的中段线direction才是有效的。
            LocateTextPanel(this.startBasePoint, this.endBasePoint, this.direction);

            switch (arrows)
            {
                case ArrowType.All:
                    {
                        startArrowPath.Visibility = endArrowPath.Visibility = Visibility.Visible; break;
                    }
                case ArrowType.End:
                    {
                        startArrowPath.Visibility = Visibility.Hidden;
                        endArrowPath.Visibility = Visibility.Visible;
                        break;
                    }
                case ArrowType.Start:
                    {
                        startArrowPath.Visibility = Visibility.Visible;
                        endArrowPath.Visibility = Visibility.Hidden;
                        break;
                    }
                case ArrowType.None:
                    {
                        startArrowPath.Visibility = endArrowPath.Visibility = Visibility.Hidden; break;
                    }
            }

            //重新计算箭头位置。
            startArrowPathFigure.StartPoint = startPoint;
            Tools.ArrowPoints apStart = new Tools.ArrowPoints(
                    startArrowPathFigure.StartPoint, startBasePoint, widgetLineWidth * 2);

            startArrowPolyLineSegment.Points = new PointCollection()
            {
                apStart.ArrowLeftPoint,apStart.ArrowRightPoint,
            };
            mainPathFigure.StartPoint = apStart.ArrowRealTopPoint;

            endArrowPathFigure.StartPoint = endPoint;
            Tools.ArrowPoints apEnd = new Tools.ArrowPoints(
                endArrowPathFigure.StartPoint, endBasePoint, widgetLineWidth * 2);
            this.endArrowPolyLineSegment.Points = new PointCollection()
            {
                apEnd.ArrowLeftPoint,apEnd.ArrowRightPoint,
            };

            return true;
        }

        private bool DrawBigFishBone(Rect startRect, Rect endRect)
        {
            Point startCenter = new Point(startRect.X + startRect.Width / 2, startRect.Y + startRect.Height / 2);
            if (startCenter.Y >= endRect.Top && startCenter.Y <= endRect.Bottom) return false;

            Point endCenter = new Point(endRect.X + endRect.Width / 2, endRect.Y + endRect.Height / 2);

            Point startPoint;
            Point endPoint;
            Point centerPoint;

            if (endCenter.X > startCenter.X)
            {
                startPoint = new Point(startRect.Right, startCenter.Y);

                if (endCenter.Y > startCenter.Y)
                {
                    endPoint = new Point(endCenter.X, endRect.Top);
                    centerPoint = new Point(endPoint.X - Math.Abs(endPoint.Y - startCenter.Y) / Math.Sqrt(3),
                        startCenter.Y);

                    if (centerPoint.X < startRect.Right) return false;//空间不够。
                }
                else
                {
                    endPoint = new Point(endCenter.X, endRect.Bottom);
                    centerPoint = new Point(endPoint.X - Math.Abs(endPoint.Y - startCenter.Y) / Math.Sqrt(3),
                        startCenter.Y);

                    if (centerPoint.X < startRect.Right) return false;//空间不够。
                }
            }
            else
            {
                startPoint = new Point(startRect.Left, startCenter.Y);

                if (endCenter.Y > startCenter.Y)
                {
                    endPoint = new Point(endCenter.X, endRect.Top);
                    centerPoint = new Point(endPoint.X + Math.Abs(endPoint.Y - startCenter.Y) / Math.Sqrt(3),
                        startCenter.Y);

                    if (centerPoint.X > startRect.Left) return false;//空间不够。
                }
                else
                {
                    endPoint = new Point(endCenter.X, endRect.Bottom);
                    centerPoint = new Point(endPoint.X + Math.Abs(endPoint.Y - startCenter.Y) / Math.Sqrt(3),
                        startCenter.Y);

                    if (centerPoint.X > startRect.Left) return false;//空间不够。
                }
            }

            startPoint = FormatPoint(startPoint);
            endPoint = FormatPoint(endPoint);
            centerPoint = FormatPoint(centerPoint);

            this.startPoint = startPoint; this.endPoint = endPoint; this.centerCPPoint = centerPoint;//刷新控制点位置。

            this.mainPathFigure.StartPoint = startPoint;
            this.mainPolySegment.Points = new PointCollection(){
                        centerPoint, endPoint
                    };

            //鱼骨图不显示箭头。
            this.startArrowPath.Visibility = this.endArrowPath.Visibility = Visibility.Collapsed;
                
            return true;
        }

        private bool DrawMediumFishBone(Rect startRect, Rect endRect)
        {
            double padding = this.widgetLineWidth;
            endRect = new Rect(endRect.X - padding, endRect.Y - padding, endRect.Width + 2 * padding, endRect.Height + 2 * padding);

            Point startCenter = new Point(startRect.X + startRect.Width / 2, startRect.Y + startRect.Height / 2);
            Point endCenter = new Point(endRect.X + endRect.Width / 2, endRect.Y + endRect.Height / 2);

            //if (startCenter.Y >= endRect.Top && startCenter.Y <= endRect.Bottom) return false;//中骨只显示横线

            Point startPoint;
            Point endPoint;
            Point startCPPoint;
            Point endCPPoint;
            Point endBasePoint;

            double d = Math.Sqrt(3);

            if (endCenter.X > startCenter.X)
            {
                startPoint = new Point(startRect.Right, startCenter.Y);

                if (endCenter.Y > startCenter.Y)
                {
                    endBasePoint = endRect.BottomLeft;
                    endCPPoint = new Point(endBasePoint.X - endRect.Height / d, endBasePoint.Y - endRect.Height);
                    endPoint = new Point(endRect.Right, endCPPoint.Y);
                    startCPPoint = new Point(endRect.Left - Math.Abs(endRect.Bottom - startCenter.Y) / d, startCenter.Y);

                    //if (startCPPoint.X < startRect.Right) return false;//空间不够。//中骨只显示横线
                }
                else
                {
                    endBasePoint = endRect.TopLeft;
                    endCPPoint = new Point(endBasePoint.X - endRect.Height / d, endBasePoint.Y + endRect.Height);
                    endPoint = new Point(endRect.Right, endCPPoint.Y);
                    startCPPoint = new Point(endRect.Left - Math.Abs(endRect.Top - startCenter.Y) / d, startCenter.Y);

                    //if (startCPPoint.X < startRect.Right) return false;//空间不够。//中骨只显示横线
                }
            }
            else
            {
                startPoint = new Point(startRect.Left, startCenter.Y);

                if (endCenter.Y > startCenter.Y)
                {
                    endBasePoint = endRect.BottomRight;
                    endCPPoint = new Point(endBasePoint.X + endRect.Height / d, endBasePoint.Y - endRect.Height);
                    endPoint = new Point(endRect.Left, endCPPoint.Y);
                    startCPPoint = new Point(endRect.Right + Math.Abs(endRect.Bottom - startCenter.Y) / d, startCenter.Y);

                    //if (startCPPoint.X > startRect.Left) return false;//空间不够。//中骨只显示横线
                }
                else
                {
                    endBasePoint = endRect.TopRight;
                    endCPPoint = new Point(endBasePoint.X + endRect.Height / d, endBasePoint.Y + endRect.Height);
                    endPoint = new Point(endRect.Left, endCPPoint.Y);
                    startCPPoint = new Point(endRect.Right + Math.Abs(endRect.Top - startCenter.Y) / d, startCenter.Y);

                    //if (startCPPoint.X > startRect.Left) return false;//空间不够。//中骨只显示横线
                }
            }

            startPoint = FormatPoint(startPoint);
            endPoint = FormatPoint(endPoint);
            startCPPoint = FormatPoint(startCPPoint);

            this.startPoint = startPoint; this.endPoint = endPoint; this.centerCPPoint = startCPPoint;//刷新控制点位置。

            //this.mainPathFigure.StartPoint = startPoint;
            //this.mainPolySegment.Points = new PointCollection(){
            //            startCPPoint,endCPPoint,endPoint
            //        };

            //中骨不显示斜线，但计算斜线
            this.mainPathFigure.StartPoint = endCPPoint;
            this.mainPolySegment.Points = new PointCollection(){
                endPoint,
            };

            //鱼骨图不显示箭头。
            this.startArrowPath.Visibility = this.endArrowPath.Visibility = Visibility.Collapsed;
                
            return true;
        }

        /// <summary>
        /// 重定文本位置。
        /// </summary>
        /// <param name="startBasePoint">首基准点。</param>
        /// <param name="endBasePoint">尾基准点。</param>
        /// <param name="centerCPPoint">中基准点。</param>
        /// <param name="derection">中段线指向。</param>
        private void LocateTextPanel(Point startBasePoint, Point endBasePoint, Orientation direction)
        {
            switch (this.LineForm)
            {
                case PolyLineForms.CLine:
                case PolyLineForms.PolyLine:
                    {
                        Point textStart;
                        if (isTextAtLeftOrTop)
                        {
                            switch (direction)
                            {
                                case Orientation.Horizontal:
                                    {
                                        textStart = new Point(centerBasePoint.X
                                            - this.mainBorder.ActualWidth / 2 - this.mainBorder.Margin.Left,
                                            centerBasePoint.Y - widgetLineWidth - this.mainBorder.Margin.Top
                                            - this.mainBorder.ActualHeight - 6);
                                        break;
                                    }
                                default:
                                    {
                                        textStart = new Point(
                                            centerBasePoint.X - widgetLineWidth + this.mainBorder.Margin.Left
                                            - this.mainBorder.ActualWidth - 6,
                                            centerBasePoint.Y
                                            - this.mainBorder.ActualHeight / 2 - this.mainBorder.Margin.Top);
                                        break;
                                    }
                            }
                        }
                        else
                        {
                            switch (direction)
                            {
                                case Orientation.Horizontal:
                                    {
                                        textStart = new Point(
                                            centerBasePoint.X
                                            - this.mainBorder.ActualWidth / 2 - this.mainBorder.Margin.Left,
                                            centerBasePoint.Y + widgetLineWidth + this.mainBorder.Margin.Top);
                                        break;
                                    }
                                default:
                                    {
                                        textStart = new Point(
                                            centerBasePoint.X + widgetLineWidth + this.mainBorder.Margin.Left,
                                            centerBasePoint.Y
                                            - this.mainBorder.ActualHeight / 2 - this.mainBorder.Margin.Top);
                                        break;
                                    }
                            }
                        }

                        Canvas.SetLeft(this.mainBorder, textStart.X);
                        Canvas.SetTop(this.mainBorder, textStart.Y);

                        break;
                    }
                case PolyLineForms.LLine:
                    {
                        //翻转纵横向（中段线与尾段正好成直角）按尾段而不是中段排列。
                        Point textStart;
                        if (isTextAtLeftOrTop)
                        {
                            switch (direction)
                            {
                                case Orientation.Vertical:
                                    {
                                        textStart = new Point(centerBasePoint.X
                                            - this.mainBorder.ActualWidth / 2 - this.mainBorder.Margin.Left,
                                            centerBasePoint.Y - widgetLineWidth - this.mainBorder.Margin.Top
                                            - this.mainBorder.ActualHeight - 6);
                                        break;
                                    }
                                default:
                                    {
                                        textStart = new Point(
                                            centerBasePoint.X - widgetLineWidth + this.mainBorder.Margin.Left
                                            - this.mainBorder.ActualWidth - 6,
                                            centerBasePoint.Y
                                            - this.mainBorder.ActualHeight / 2 - this.mainBorder.Margin.Top);
                                        break;
                                    }
                            }
                        }
                        else
                        {
                            switch (direction)
                            {
                                case Orientation.Vertical:
                                    {
                                        textStart = new Point(
                                            centerBasePoint.X
                                            - this.mainBorder.ActualWidth / 2 - this.mainBorder.Margin.Left,
                                            centerBasePoint.Y + widgetLineWidth + this.mainBorder.Margin.Top);
                                        break;
                                    }
                                default:
                                    {
                                        textStart = new Point(
                                            centerBasePoint.X + widgetLineWidth + this.mainBorder.Margin.Left,
                                            centerBasePoint.Y
                                            - this.mainBorder.ActualHeight / 2 - this.mainBorder.Margin.Top);
                                        break;
                                    }
                            }
                        }

                        Canvas.SetLeft(this.mainBorder, textStart.X);
                        Canvas.SetTop(this.mainBorder, textStart.Y);

                        break;
                    }
                default: break;//鱼骨图等不支持文本显示。
            }
        }

        private Point FormatStartMovingPoint(Point newInsideMovingPoint, Point endPoint)
        {
            double horizontalDistance = newInsideMovingPoint.X - endPoint.X;
            double verticalDistance = newInsideMovingPoint.Y - endPoint.Y;

            double absHD = Math.Abs(horizontalDistance);
            double absVD = Math.Abs(verticalDistance);

            if (absVD > absHD)
            {
                if (absVD > absHD * 2)
                {
                    newInsideMovingPoint = new Point(endPoint.X, newInsideMovingPoint.Y);
                }
                else
                {
                    int qua = Getquadrant(newInsideMovingPoint, endPoint);
                    switch (qua)
                    {
                        case 1:
                            {
                                newInsideMovingPoint = new Point(newInsideMovingPoint.X,
                                   endPoint.Y - (newInsideMovingPoint.X - endPoint.X));
                                break;
                            }
                        case 2:
                            {
                                newInsideMovingPoint = new Point(newInsideMovingPoint.X,
                                   endPoint.Y + (newInsideMovingPoint.X - endPoint.X));
                                break;
                            }
                        case 3:
                            {
                                newInsideMovingPoint = new Point(newInsideMovingPoint.X,
                                   endPoint.Y - (newInsideMovingPoint.X - endPoint.X));
                                break;
                            }
                        case 4:
                            {
                                newInsideMovingPoint = new Point(newInsideMovingPoint.X,
                                    endPoint.Y + (newInsideMovingPoint.X - endPoint.X));
                                break;
                            }
                    }
                }
            }
            else
            {
                if (absVD * 2 < absHD)
                {
                    newInsideMovingPoint = new Point(newInsideMovingPoint.X, endPoint.Y);
                }
                else
                {
                    int qua = Getquadrant(newInsideMovingPoint, endPoint);
                    switch (qua)
                    {
                        case 1:
                            {
                                newInsideMovingPoint = new Point(newInsideMovingPoint.X,
                                   endPoint.Y - (newInsideMovingPoint.X - endPoint.X));
                                break;
                            }
                        case 2:
                            {
                                newInsideMovingPoint = new Point(newInsideMovingPoint.X,
                                   endPoint.Y + (newInsideMovingPoint.X - endPoint.X));
                                break;
                            }
                        case 3:
                            {
                                newInsideMovingPoint = new Point(newInsideMovingPoint.X,
                                   endPoint.Y - (newInsideMovingPoint.X - endPoint.X));
                                break;
                            }
                        case 4:
                            {
                                newInsideMovingPoint = new Point(newInsideMovingPoint.X,
                                    endPoint.Y + (newInsideMovingPoint.X - endPoint.X));
                                break;
                            }
                    }
                }
            }

            return newInsideMovingPoint;
        }

        /// <summary>
        /// 以basePoint为基础坐标，画出四象限。
        /// 取出pt在哪个象限中。
        /// </summary>
        /// <param name="pt"></param>
        /// <param name="basePoint"></param>
        /// <returns></returns>
        private int Getquadrant(Point pt, Point basePoint)
        {
            if (pt.X > basePoint.X)
            {
                if (pt.Y > basePoint.Y)
                {
                    return 4;
                }
                else
                {
                    return 1;
                }
            }
            else
            {
                if (pt.Y > basePoint.Y)
                {
                    return 3;
                }
                else
                {
                    return 2;
                }
            }
        }

        public override string GetRelativeOuterXml(Point baseCopyTopLeft)
        {
            if (this.xmlData == null) return string.Empty;

            Point oldStartPoint = startPoint;
            Point newStartPoint = new Point(oldStartPoint.X - baseCopyTopLeft.X,
                oldStartPoint.Y - baseCopyTopLeft.Y);
            this.xmlData.SetAttribute(XmlTags.StartPointTag, newStartPoint.ToString());

            Point oldCenterCPPoint = centerCPPoint;
            Point newCenterCPPoint = new Point(oldCenterCPPoint.X - baseCopyTopLeft.X,
                oldCenterCPPoint.Y - baseCopyTopLeft.Y);
            this.xmlData.SetAttribute(XmlTags.CenterCPPointTag, newCenterCPPoint.ToString());

            Point oldEndPoint = endPoint;
            Point newEndPoint = new Point(oldEndPoint.X - baseCopyTopLeft.X,
                oldEndPoint.Y - baseCopyTopLeft.Y);
            this.xmlData.SetAttribute(XmlTags.EndPointTag, newEndPoint.ToString());

            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            sb.Append(this.xmlData.OuterXml);

            this.xmlData.SetAttribute(XmlTags.StartPointTag, oldStartPoint.ToString());
            this.xmlData.SetAttribute(XmlTags.CenterCPPointTag, oldCenterCPPoint.ToString());
            this.xmlData.SetAttribute(XmlTags.EndPointTag, oldEndPoint.ToString());
            return sb.ToString();
        }
        
        public override void RefreshArrows()
        {
            this.RefreshArrows(true);
        }

        /// <summary>
        /// 刷新箭头状态。
        /// </summary>
        /// <param name="drawLine">若为真，按已设置的startPoint/startCPpoint/endCPPoint/endPoint画线及箭头。</param>
        private void RefreshArrows(bool drawLine)
        {
            base.RefreshArrows();

            if (drawLine) DrawLine();
        }
        
        public override void RefreshLineDash()
        {
            switch (lineDash)
            {
                case LineDashType.DashType.Dash:
                    {
                        this.mainPath.StrokeDashArray = LineDashType.dashCollection; break;
                    }
                case LineDashType.DashType.DashDotDot:
                    {
                        this.mainPath.StrokeDashArray = LineDashType.dashDotDotCollection; break;
                    }
                case LineDashType.DashType.Dot:
                    {
                        this.mainPath.StrokeDashArray = LineDashType.dotCollection; break;
                    }
                case LineDashType.DashType.Solid:
                    {
                        this.mainPath.StrokeDashArray = LineDashType.solidCollection; break;
                    }
                default:
                    {
                        this.mainPath.StrokeDashArray = LineDashType.dashDotCollection; break;
                    }
            }
        }

        public void RefreshLineForm()
        {
            this.DrawLine();
            this.RefreshIsTextVisible();

            if (this.mainTextPanel.Visibility == Visibility.Visible)
            {
                this.RefreshTextPanelLocatin();
            }
        }
        
        /// <summary>
        /// 刷新线宽。
        /// </summary>
        public override void RefreshWidgetLineWidth()
        {
            base.RefreshWidgetLineWidth();

            //强制折线跳过宽度１（当作２看待）——因为会模糊，很难看。
            //mainPath.StrokeThickness = (lineWidth < 2 ? 2 : lineWidth);

            double newLineWidth = (widgetLineWidth < 1 ? 1 : widgetLineWidth);
            mainPath.StrokeThickness = newLineWidth;//还是支持宽度1的线为妙。

            if (widgetLineWidth == 1)
            {
                RenderOptions.SetEdgeMode(mainPath, EdgeMode.Aliased);
            }
            else
            {
                RenderOptions.SetEdgeMode(mainPath, EdgeMode.Unspecified);
            }

            startArrowPath.StrokeThickness = endArrowPath.StrokeThickness = newLineWidth;
        }

        public override void RefreshLocation()
        {
            base.RefreshLocation();

            RefreshWidgetLineWidth();
            RefreshArrows();

            DrawLine();
        }

        public override void RefreshPointWhenGroupIn(Point baseTopLeft)
        {
            Point oldStartPoint = startPoint;
            Point newStartPoint = new Point(oldStartPoint.X - baseTopLeft.X,
                oldStartPoint.Y - baseTopLeft.Y);
            StartPoint = newStartPoint;

            Point oldCenterCPPoint = centerCPPoint;
            Point newCenterCPPoint = new Point(oldCenterCPPoint.X - baseTopLeft.X,
                oldCenterCPPoint.Y - baseTopLeft.Y);
            CenterCPPoint = newCenterCPPoint;

            Point oldEndPoint = endPoint;
            Point newEndPoint = new Point(oldEndPoint.X - baseTopLeft.X,
                oldEndPoint.Y - baseTopLeft.Y);
            EndPoint = newEndPoint;
        }

        public override void RefreshPointWhenGroupOut(Point baseTopLeft)
        {
            Point oldStartPoint = startPoint;
            Point newStartPoint = new Point(oldStartPoint.X + baseTopLeft.X,
                oldStartPoint.Y + baseTopLeft.Y);
            StartPoint = newStartPoint;

            Point oldCenterCPPoint = centerCPPoint;
            Point newCenterCPPoint = new Point(oldCenterCPPoint.X + baseTopLeft.X,
                oldCenterCPPoint.Y + baseTopLeft.Y);
            CenterCPPoint = newCenterCPPoint;

            Point oldEndPoint = endPoint;
            Point newEndPoint = new Point(oldEndPoint.X + baseTopLeft.X,
                oldEndPoint.Y + baseTopLeft.Y);
            EndPoint = newEndPoint;
        }

        public override void RefreshWidgetLineColor()
        {
            startArrowPath.Stroke = endArrowPath.Stroke =
                startArrowPath.Fill = endArrowPath.Fill =
                    mainPath.Stroke = WidgetLineColor;
        }
        
        public override void RefreshIsShadowVisible()
        {
            base.RefreshIsShadowVisible();

            if (isShadowVisible)
            {
                this.mainPath.Effect = Widget.ShadowEffect;
            }
            else
            {
                this.mainPath.Effect = null;
            }
        }

        /// <summary>
        /// 仅在为PolyLine或CLine或LLine形态时有效。
        /// </summary>
        public override void RefreshTextPanelLocatin()
        {
            switch (this.LineForm)
            {
                case PolyLineForms.CLine:
                case PolyLineForms.LLine:
                case PolyLineForms.PolyLine:
                    {
                        Point startBasePoint = this.startBasePoint;
                        Point endBasePoint = this.endBasePoint;

                        RefreshTextPanelLocatin(ref startBasePoint, ref endBasePoint, ref centerBasePoint, this.direction);
                        break;
                    }
            }
        }

        private void RefreshTextPanelLocatin(ref Point startBasePoint, ref Point endBasePoint, ref Point centerBasePoint, Orientation direction)
        {
            LocateTextPanel(startBasePoint, endBasePoint, direction);
        }

        public override void RefreshIsTextVisible()
        {
            switch (this.lineForm)
            {
                case PolyLineForms.BigFishBone:
                case PolyLineForms.MediumFishBone:
                    {
                        this.mainTextPanel.Visibility = Visibility.Collapsed;
                        break;
                    }
                default:
                    {
                        base.RefreshIsTextVisible();
                        break;
                    }
            }
        }
        
        #endregion


        #region 其它=========================================================================================================

        //private enum ControlDraggingType { Start, End, None, CenterCP }
        //2012年5月30日已移植并合并至Enums.LineCtrlDraggingType文件中。

        private static DoubleCollection dashArray;

        #endregion
    }
}
